package limiter

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"goTestToMod/rate_limiter_byId/global"
	"goTestToMod/rate_limiter_byId/utility"
	"strconv"
	"strings"
	"sync"
	"time"
)

var once sync.Once

var HASH_NAME = fmt.Sprintf("TESTCENTER_%s_TESTLIB_TOKEN_BUCKET_LIMIT" , "dev1")
const (
	empNo = "X-Emp-No"
	SEPERATOR = "___"
)

func GetLimiter(rate, cap int) *MidWareLimiter {
	empLimiter := &MidWareLimiter{}
	empLimiter.Rate = rate
	empLimiter.Cap = cap
	return empLimiter
}

type MidWareLimiter struct{
	Rate int
	Cap  int
}

func (l *MidWareLimiter) IsLimit(ctx *gin.Context) (bool, error) {
	head, err := utility.HandleHead(ctx.Request.Header)
	if err != nil {
		return true, err
	}
	if empNum, ok  := head[empNo]; ok {
		methd := ctx.Request.Method
		uri := ctx.Request.URL.Path
		hashStr := utility.GetStringHash(methd+uri+empNum)
		val, err := global.RedisClient.HGet(HASH_NAME, hashStr).Result()

		if err != nil {
			return true, err
		}
		var currentTokenCount string
		var lastTime string
		if val == "" {
			currentTokenCount = strconv.Itoa(l.Cap)
			lastTime = strconv.FormatInt(time.Now().Unix(), 10)
		} else {
			currentTokenCount = strings.Split(val, SEPERATOR)[0]
			lastTime = strings.Split(val, SEPERATOR)[1]
		}
		lastTimeInt64, _ := strconv.ParseInt(lastTime, 10, 64)
		currentTokenCountInt64, _ := strconv.ParseInt(currentTokenCount, 10, 64)
		timeNow := time.Now().Unix()
		increaseTokens := (timeNow - lastTimeInt64) * int64(l.Rate)
		currentTokenCountInt64 = utility.Min(int64(l.Cap), currentTokenCountInt64 + increaseTokens)
		if currentTokenCountInt64 > 0 {
			_, err := global.RedisClient.HSet(HASH_NAME, hashStr, fmt.Sprintf("%d%s%d", currentTokenCountInt64-1, SEPERATOR, timeNow)).Result()
			if err != nil {
				panic(err.Error())
			}
			return false, nil
		} else {
			return true, fmt.Errorf("限流器限流")
		}
	}
	return false, fmt.Errorf("No X-Emp-No !!")
}



